﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Browser;


// $Id:$

namespace WebBuddy.UriBuddy
{
    /// <summary>
    /// Cool extensions to make life in URI land easy.
    /// </summary>
    public static class UriBuddyExtensions
    {
        /// <summary>
        /// Convert to query parameters
        /// </summary>
        ///<example><code source="..\UriBuddyExtensions.cs" lang="C#" region="UriExtensionExample" title="Using These Extensions"/></example>
        /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
        /// <param name="list">The Dictionary from which to build the query string</param>
        /// <param name="provider">An <see cref="IFormatProvider"/> that supplies culture-specific formatting information. </param>
        /// <param name="keyProjection">The function to convert from <typeparamref name="TKey"/> to <typeparamref name="String"/></param>
        /// <param name="valueProjection">The function to convert from <typeparamref name="TValue"/> to <typeparamref name="String"/></param>
        /// <returns>A <see cref="IEnumerable{T}"/> that has combined the keys and values</returns>
        public static IEnumerable<String> ToQueryParams<TKey, TValue>(
            this IEnumerable<KeyValuePair<TKey, TValue>> list,
            IFormatProvider provider,
            Func<TKey, String> keyProjection,
            Func<TValue, String> valueProjection)
        {
            return list.Select(
                s => String.Format(
                    provider,
                    "{0}={1}",
                    keyProjection(s.Key),
                    valueProjection(s.Value)
                 )
            );

        }



        /// <summary>
        /// Builds a Query String.
        /// </summary>
        ///<example><code source="..\UriBuddyExtensions.cs" lang="C#" region="UriExtensionExample"/></example>
        /// <param name="list">The Dictionary from which to build the query string</param>
        /// <param name="seperator">The seperator used to seperate each key/value pair</param>
        /// <param name="options">Specifies the encoder options used for creating the query string</param>
        /// <param name="provider">An <see cref="IFormatProvider"/> that supplies culture-specific formatting information. </param>
        /// <returns>A query string.</returns>
        /// <remarks>This function will properly URL encode both the key and value.  It calls the <see cref="System.String.ToString()"/> on both keys and values</remarks>
        public static String ToQueryString(
            this IEnumerable<KeyValuePair<String, String>> list,
            string seperator,
            UrlEncoderOptions options,
            IFormatProvider provider)
        {

            IEnumerable<String> joins =
                list.ToQueryParams(provider,
                    ( s => options.IsSet(UrlEncoderOptions.EncodeKeys) ? HttpUtility.UrlEncode(s) : s ),
                    ( s => options.IsSet(UrlEncoderOptions.EncodeValues) ? HttpUtility.UrlEncode(s) : s ));


            return joins.Aggregate((forming, ours) => forming + seperator + ours);
        }

        /// <summary>
        /// Builds a Query String.
        /// </summary>
        ///<example><code source="..\UriBuddyExtensions.cs" lang="C#" region="UriExtensionExample" title="Using These Extensions"/></example>
        /// <param name="list">The Dictionary from which to build the query string</param>
        /// <param name="seperator">The seperator used to seperate each key/value pair</param>
        /// <param name="options">Specifies the encoder options used for creating the query string</param>
        /// <returns>A query string.</returns>
        /// <remarks>This function will properly URL encode both the key and value. It will use the InvariantCulture for formatting.  It calls the <see cref="System.String.ToString()"/> on both keys and values</remarks>
        /// <overloads>
        /// This method has several overloads.
        ///<example><code source="..\UriBuddyExtensions.cs" lang="C#" region="UriExtensionExample" title="Using These Extensions"/></example>
        /// </overloads>
        public static String ToQueryString(
            this IEnumerable<KeyValuePair<String, String>> list,
            string seperator,
            UrlEncoderOptions options)
        {
            return list.ToQueryString(seperator, options, System.Globalization.CultureInfo.InvariantCulture);

        }
        /// <summary>
        /// Builds a Query String seperated using the &amp;
        /// </summary>
        /// <param name="list">The Dictionary from which to build the query string</param>
        /// <returns>A query string.</returns>
        /// <remarks>This function will properly URL encode both the key and value.  It calls the <see cref="System.String.ToString()"/> on both keys and values</remarks>
        public static String ToQueryString(
            this IEnumerable<KeyValuePair<String, String>> list
        )
        {

            return list.ToQueryString("&", UrlEncoderOptions.EncodeKeys | UrlEncoderOptions.EncodeValues, System.Globalization.CultureInfo.InvariantCulture);

        }

        /// <summary>
        /// Builds a query string from a Dictionary
        /// </summary>
        /// <param name="builder">The <see cref="UriBuilder"/> to add the query string to</param>
        /// <param name="list">A list of key/value pairs to use</param>
        public static void BuildQueryString(this UriBuilder builder, IDictionary<String, String> list)
        {
            builder.Query = list.ToQueryString("&", UrlEncoderOptions.EncodeValues | UrlEncoderOptions.EncodeKeys);
        }

        /// <summary>
        /// Append a list of query values to a Uri
        /// </summary>
        /// <param name="baseUri">The base component of this uri</param>
        /// <param name="queryValues">A <see cref="IDictionary{T,T}"/> with a bunch of query values</param>
        /// <returns>A new URI with your query values on the end.</returns>
        public static Uri AppendQueryValues(this Uri baseUri, IDictionary<String, String> queryValues)
        {
            UriBuilder ub = new UriBuilder(baseUri);
            ub.BuildQueryString(queryValues);
            return ub.Uri;
        }

        /// <summary>
        /// Append a query string
        /// </summary>
        /// <param name="baseUri">The base component of this uri</param>
        /// <param name="queryString">The query string</param>
        /// <returns>A new URI that uses the query string</returns>
        public static Uri AppendQueryString(this Uri baseUri, string queryString)
        {
            UriBuilder ub = new UriBuilder(baseUri);
            ub.Query = queryString;
            return ub.Uri;
        }

        /// <summary>
        /// Append a path component to a uri.
        /// </summary>
        /// <param name="baseUri">The base component of this uri</param>
        /// <param name="relativePath">A relative path component of a uri</param>
        /// <returns>A new Uri that uses the query string</returns>
        public static Uri AppendPath(this Uri baseUri, string relativePath)
        {
            Uri outUri;

            if ( Uri.TryCreate(baseUri, relativePath, out outUri) )
                return outUri;
            else
                return baseUri;
        }
    }
}
